#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <assert.h>

int main(int argc, char **argv) {
   
    fd_set tmp, readfd;
    struct timeval timeout;
    int maxfd = 0;
    struct sockaddr_in addr;
    int listenfd = socket(PF_INET, SOCK_STREAM, 0);
    printf("listenfd = %d\n", listenfd);

    if (argc != 2) {
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(atoi(argv[1]));

    int rs = bind(listenfd, (struct sockaddr *)&addr, sizeof addr);
    assert(rs != -1);
    rs = listen(listenfd, 5);
    assert(rs != -1);
    // 加入listenfd
    FD_ZERO(&readfd);
    FD_SET(listenfd, &readfd);
    maxfd = listenfd;

     
    while (1) {
        tmp = readfd;
        timeout.tv_sec = 5;
        timeout.tv_usec = 5000;
        int res = select(maxfd + 1, &tmp, 0, 0, &timeout);
        if (res == 0) {
            puts("timeout !");
            continue;
        } else if (res == -1) {
            puts("select error!");
            break;
        } else {
            for (int i = 0; i <= maxfd; i++) {
                if (!FD_ISSET(i, &tmp))  continue;
                if (i == listenfd) {
                    struct sockaddr_in client_addr;
                    int sz = sizeof(client_addr);
                    int connfd = accept(listenfd, (struct sockaddr*)&client_addr, &sz);
                    FD_SET(connfd, &readfd);
                    if (connfd > maxfd) 
                        maxfd = connfd;
                    printf("connected client %d\n", connfd);
                } else {    
                    char buf[512] = {0};
                    int str_len = read(i, buf, 512);
                    if (str_len == 0) {
                        // eof
                        FD_CLR(i, &readfd);
                        close(i);
                        printf("closed client %d \n", i);
                    } else {
                        // echo
                        write(i, buf, str_len);
                    }
                }
            }
        }
    }
    close(listenfd);
    return 0;
}